#pragma once

#include <ngx_config.h>
#include <ngx_core.h>
#include <pthread.h>
#include <hiredis/hiredis.h>

#define REDIS_HOST	"localhost"
#define REDIS_PORT	6379

struct ngx_redis_client {
	pthread_mutex_t lock;
	redisContext *context;
	const char *host;
	int port;
	struct ngx_redis_client *next;
};

struct ngx_redis_pool {
	pthread_mutex_t lock;
	pthread_cond_t cond;
	int links;
	struct ngx_redis_client *head;
};

extern struct ngx_redis_pool gRedisPool;

void ngx_redis_client_init(struct ngx_redis_client *redis);
void ngx_redis_client_deinit(struct ngx_redis_client *redis);

redisContext *ngx_redis_connect(struct ngx_redis_client *redis);
void ngx_redis_disconnect(struct ngx_redis_client *redis);
redisReply *ngx_redis_execute(struct ngx_redis_client *redis, int argc, const char *argv[], const size_t argvl[]);

struct ngx_redis_client *ngx_redis_get(struct ngx_redis_pool *pool);
void ngx_redis_put(struct ngx_redis_pool *pool, struct ngx_redis_client *redis);

static inline void ngx_redis_client_lock(struct ngx_redis_client *redis)
{
	pthread_mutex_lock(&redis->lock);
}

static inline void ngx_redis_client_unlock(struct ngx_redis_client *redis)
{
	pthread_mutex_unlock(&redis->lock);
}

static inline void ngx_redis_pool_lock(struct ngx_redis_pool *pool)
{
	pthread_mutex_lock(&pool->lock);
}

static inline void ngx_redis_pool_unlock(struct ngx_redis_pool *pool)
{
	pthread_mutex_unlock(&pool->lock);
}

static inline void ngx_redis_pool_wait(struct ngx_redis_pool *pool)
{
	pthread_cond_wait(&pool->cond, &pool->lock);
}

static inline void ngx_redis_pool_timedwait(struct ngx_redis_pool *pool, int msec)
{
	struct timespec ts;

	clock_gettime(CLOCK_REALTIME, &ts);

	msec += ts.tv_nsec / 1000000L;
	ts.tv_sec += msec / 1000;
	ts.tv_nsec = (msec % 1000) * 1000000L;

	pthread_cond_timedwait(&pool->cond, &pool->lock, &ts);
}

static inline void ngx_redis_pool_notify(struct ngx_redis_pool *pool)
{
	pthread_cond_signal(&pool->cond);
}

static inline struct ngx_redis_client *ngx_redis_simple_get(void)
{
	return ngx_redis_get(&gRedisPool);
}

static inline void ngx_redis_simple_put(struct ngx_redis_client *redis)
{
	ngx_redis_put(&gRedisPool, redis);
}
